package cn.hg.solon.youcan.system.provider;

import cn.hg.solon.youcan.common.enums.BeanStatus;
import cn.hg.solon.youcan.common.exception.ServiceException;
import cn.hg.solon.youcan.flex.util.QueryWrapperUtil;
import cn.hg.solon.youcan.system.entity.*;
import cn.hg.solon.youcan.system.mapper.SysRoleDeptMappingMapper;
import cn.hg.solon.youcan.system.mapper.SysRoleMapper;
import cn.hg.solon.youcan.system.mapper.SysRolePermissionMappingMapper;
import cn.hg.solon.youcan.system.service.RoleService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.solon.service.impl.ServiceImpl;
import org.apache.ibatis.solon.annotation.Db;
import org.dromara.hutool.core.bean.BeanUtil;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.convert.ConvertUtil;
import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.text.StrValidator;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.db.PageResult;
import org.noear.solon.annotation.Component;
import org.noear.solon.data.annotation.Tran;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static cn.hg.solon.youcan.system.entity.table.SysRoleDeptMappingTableDef.SYS_ROLE_DEPT_MAPPING;
import static cn.hg.solon.youcan.system.entity.table.SysRolePermissionMappingTableDef.SYS_ROLE_PERMISSION_MAPPING;
import static cn.hg.solon.youcan.system.entity.table.SysRoleTableDef.SYS_ROLE;
import static cn.hg.solon.youcan.system.entity.table.SysUserRoleMappingTableDef.SYS_USER_ROLE_MAPPING;
import static cn.hg.solon.youcan.system.entity.table.SysUserTableDef.SYS_USER;

/**
 * @author 胡高
 */
@Component
public class SysRoleProvider extends ServiceImpl<SysRoleMapper, SysRole> implements RoleService {

    @Db
    private SysRoleDeptMappingMapper roleDeptMappingMapper;

    @Db
    private SysRolePermissionMappingMapper rolePermissionMappingMapper;

    @Override
    public void assignDataScope(Role role, String dataScope, List<Integer> deptIds) {
        /*
         * 删除所有部门
         */
        this.roleDeptMappingMapper.deleteByCondition(SYS_ROLE_DEPT_MAPPING.ROLE_ID.eq(role.getId()));

        /*
         * 重新建立角色权限
         */
        List<SysRoleDeptMapping> beanList = new ArrayList<>();
        for (int id : deptIds) {
            SysRoleDeptMapping bean = new SysRoleDeptMapping();
            bean.setRoleId(role.getId());
            bean.setDeptId(id);

            beanList.add(bean);
        }

        if (CollUtil.isNotEmpty(beanList)) {
            this.roleDeptMappingMapper.insertBatch(beanList);
        }

        role.setDataScope(dataScope);

        this.update(role);
    }

    @Override
    public void assignPermission(Role role, List<Integer> permissionIds) {
        /*
         * 删除所有权限
         */
        this.rolePermissionMappingMapper.deleteByCondition(SYS_ROLE_PERMISSION_MAPPING.ROLE_ID.eq(role.getId()));

        /*
         * 重新建立角色权限
         */
        List<SysRolePermissionMapping> beanList = new ArrayList<>();
        for (int id : permissionIds) {
            SysRolePermissionMapping bean = new SysRolePermissionMapping();
            bean.setRoleId(role.getId());
            bean.setPermissionId(id);

            beanList.add(bean);
        }

        if (CollUtil.isNotEmpty(beanList)) {
            this.rolePermissionMappingMapper.insertBatch(beanList);
        }
    }

    private QueryWrapper buildQuery(org.dromara.hutool.db.Page page, Map<String, Object> paraMap) {
        String word = (String) paraMap.get("word");
        String status = (String) paraMap.get("status");

        QueryWrapper query = QueryWrapper.create()
                .where(SYS_ROLE.STATUS.eq(status).when(StrValidator.isNotBlank(status)).and(SYS_ROLE.NAME.like(word)
                        .when(StrValidator.isNotBlank(word)).or(SYS_ROLE.CODE.like(word).when(StrValidator.isNotBlank(word)))));

        return QueryWrapperUtil.applyOrderBy(query, page);
    }

    @Override
    public boolean checkUnique(Role bean) {
        // 查找已存在记录
        QueryWrapper query =
                QueryWrapper.create().where(SYS_ROLE.CODE.eq(bean.getCode()).and(SYS_ROLE.ID.ne(bean.getId())));

        return ObjUtil.isNull(this.getOne(query));
    }

    @Tran
    @Override
    public boolean delete(List<Integer> idList) {
        if (CollUtil.contains(idList, Integer.valueOf(1))) {
            throw new ServiceException("初始的 超级管理员角色 不允许删除！");
        }

        for (Integer id : idList) {
            QueryWrapper query = QueryWrapper.create().select().from(SYS_ROLE).leftJoin(SYS_USER_ROLE_MAPPING)
                    .on(SYS_USER_ROLE_MAPPING.ROLE_ID.eq(SYS_ROLE.ID)).leftJoin(SYS_USER)
                    .on(SYS_USER_ROLE_MAPPING.USER_ID.eq(SYS_USER.ID))
                    .where(SYS_ROLE.ID.eq(id));

            if (this.getMapper().selectCountByQuery(query) > 0) {
                throw new ServiceException("角色已经分配给用户，不允许删除！");
            }
        }

        return this.getMapper().deleteBatchByIds(idList) > 0;
    }

    @Override
    public SysRole get(Integer id) {
        return this.getMapper().selectOneById(id);
    }

    @Override
    public SysRole getByCode(String code) {
        QueryWrapper query = QueryWrapper.create().where(SYS_ROLE.CODE.eq(code));
        return this.getMapper().selectOneByQuery(query);
    }

    @Tran
    @Override
    public boolean insert(Role bean, List<Integer> deptIds, List<Integer> permissionIds) {
        if (!this.checkUnique(bean)) {
            throw new ServiceException("权限代码已经存在，请更换其它值！");
        }

        SysRole cloneBean = BeanUtil.copyProperties(bean, SysRole.class);

        boolean ret = this.getMapper().insert(cloneBean) > 0;

        // 指派数据权限
        this.assignDataScope(cloneBean, bean.getDataScope(), deptIds);

        // 指派系统权限
        this.assignPermission(cloneBean, permissionIds);

        return ret;
    }

    @Override
    public List<SysRole> listBy(Map<String, Object> paraMap) {
        return this.getMapper().selectListByQuery(this.buildQuery(null, paraMap));
    }

    @Override
    public List<SysRole> listByStatus(String status) {
        return this.getMapper().selectListByQuery(this.buildQuery(null, MapUtil.of("status", status)));
    }

    @Override
    public List<SysRole> listByUser(User bean) {
        if (ObjUtil.isNull(bean)) {
            return ListUtil.empty();
        }

        if (bean.getId() == 1) {
            return this.list(SYS_ROLE.STATUS.eq(BeanStatus.ON.name()));
        }

        /*
            SELECT r.*
            FROM sys_role AS r
                LEFT JOIN sys_user_role_mapping AS ur ON ur.role_id = r.id
            WHERE ur.user_id = #para(userId)
            ORDER BY r.sort
         */
        QueryWrapper query = QueryWrapper.create()
                .leftJoin(SYS_USER_ROLE_MAPPING).on(SYS_USER_ROLE_MAPPING.ROLE_ID.eq(SYS_ROLE.ID))
                .where(SYS_USER_ROLE_MAPPING.USER_ID.eq(bean.getId()))
                .orderBy(SYS_ROLE.SORT.getName());

        return this.getMapper().selectListByQuery(query);
    }

    @Override
    public PageResult<SysRole> pageBy(org.dromara.hutool.db.Page page, Map<String, Object> paraMap) {
        Page<SysRole> pageList = this.getMapper().paginate(Page.of(page.getPageNumber(), page.getPageSize()),
                this.buildQuery(page, paraMap));

        PageResult<SysRole> result = new PageResult<>();
        result.addAll(pageList.getRecords());
        result.setTotal(ConvertUtil.toInt(pageList.getTotalRow()));

        return result;
    }

    @Tran
    @Override
    public boolean update(Role bean) {
        if (!this.checkUnique(bean)) {
            throw new ServiceException("权限代码已经存在，请更换其它值！");
        }

        SysRole cloneBean = BeanUtil.copyProperties(bean, SysRole.class);

        return this.getMapper().update(cloneBean) > 0;
    }

}
